/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.security.server.servlet;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.core.Ordered;
import org.tianyun.cloud.exception.NestedException;
import org.tianyun.cloud.security.configuration.SecurityProperties;
import org.tianyun.cloud.security.server.SecurityFilterChainBuilder;
import org.tianyun.cloud.security.server.SecurityWebExchange;
import reactor.core.publisher.Mono;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * 安全过滤器，ServletSecurityFilter的代理
 *
 * @auther ebert_chan
 */
public class ServletSecurityFilterProxy implements Filter, Ordered {

    /**
     * 高优先级Filter，通常系统框架使用
     */
    public static final int HIGHEST_PRECEDENCE_FILTER = 0;

    private SecurityProperties securityProperties;

    private List<ServletSecurityFilter> servletSecurityFilters;

    public ServletSecurityFilterProxy(SecurityProperties securityProperties, List<ServletSecurityFilter> servletSecurityFilters) {
        this.securityProperties = securityProperties;
        this.setServletSecurityFilters(servletSecurityFilters);
    }

    public void setServletSecurityFilters(List<ServletSecurityFilter> servletSecurityFilters) {
        this.servletSecurityFilters = servletSecurityFilters;
        if (!CollectionUtils.isEmpty(servletSecurityFilters)) {
            this.servletSecurityFilters.sort((o1, o2) -> {
                return o1.getOrder() == o2.getOrder() ? 0 : (o1.getOrder() > o2.getOrder() ? 1 : -1);
            });
        }
    }

    /*
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (CollectionUtils.isEmpty(servletSecurityFilters) || !securityProperties.isEnabled()) {
            chain.doFilter(request, response);
            return;
        }

        SecurityFilterChainBuilder<ServletRequest, ServletResponse> builder = SecurityFilterChainBuilder.servlet();

        for (ServletSecurityFilter servletSecurityFilter : servletSecurityFilters) {
            builder.addSecurityFilter(servletSecurityFilter);
        }

        SecurityWebExchange<ServletRequest, ServletResponse> webExchange = new SimpleSecurityWebExchange(request, response);
        Mono<Void> mono = builder.build().doFilter(webExchange);
        if (mono != null) {
            try {
                mono.block();
            } catch (Throwable e) {
                throw new NestedException("unknown exception", e);
            }
            chain.doFilter(request, response);
        }
    }

    /*
     * @see org.springframework.core.Ordered#getOrder()
     */
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE_FILTER + 10;
    }

}
